home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / ASSEMBLE / 0938.ZIP / KEGELUNX.ARC / LS.ASM < prev    next >
Assembly Source File  |  1986-05-07  |  24KB  |  1,244 lines

  1.     page    66,132
  2.     page
  3.  
  4. ;---- ls.com ---------------------------------------------------------------
  5. ; Usage: ls {-options} {name}
  6. ; Lists files on given directory.
  7. ; Default is current directory.
  8. ; Options: alsR1
  9. ;  a- show all system & hidden files, too
  10. ;  l- long format- show size, protection, time of last modification.
  11. ;  s- show size.
  12. ;  R- recursive- show contents of all subdirectories, too
  13. ;  1- one file per line (default is multicolumnar output, unless -l or -s).
  14. ; DRK 24 July 84
  15. ; CCW March 1985 - changed over to sprintf, improved -l
  16. ; DRK 7 April 1985 - fixed tens digit in minutes in -l
  17. ; DRK 7 May 1986 - ripped out stupid _ code, added .. kludge for DOS 3.x
  18. ;------------------------------------------------------------------------------
  19. ; main(argc, argv);
  20. ; int argc;
  21. ; char *argv;
  22. ; {
  23. ;    char    fname[128];
  24. ;
  25. ;    /* The main program prepares the argument for passing to the
  26. ;       recursive CHECKFILE procelsre.
  27. ;       This is the same preparation needed in the program LS. */
  28. ;
  29. ;    sea_atr = directory;        /* includes normal files */
  30. ;    if (opt_a)
  31. ;        sea_atr = hidden + directory;
  32. ;
  33. ;    if (argv > 1) error;
  34. ;    
  35. ;    fname[0] = '/0';
  36. ;    if (argc > 0) strcpy(fname, argv[2]);
  37. ;
  38. ;    /* No argument, or default directory? */
  39. ;    if (fname[0] == '\0' || (fname[0] == '.' && fname[1] == '\0'))
  40. ;        /* leave a drive specifier for next if statement */
  41. ;        fname[0] = 'A' + current_drive;
  42. ;        fname[1] = ':';
  43. ;        fname[2] = '\0';
  44. ;        }
  45. ;
  46. ;    /* Drive specifier only?  If so, get default directory for that drive */
  47. ;    if (fname[1] == ':' && fname[2] == '\0') {
  48. ;        fname[2] = '\';
  49. ;        getpath(fname+3, toupper(fname[0])-'A'+1 );
  50. ;        if (fname[3] != 0)        /* root directory */
  51. ;            strappend(fname, "\");
  52. ;        }
  53. ;
  54. ;    /* Is it wildcarded?  If so, it cannot be a directory. */
  55. ;    for (i=0; i<strlen(fname); i++)
  56. ;        wild = (fname[i] in ['?', '*']);
  57. ;
  58. ;    /* Is it a directory (does it end with a slash) ? */
  59. ;    if (!wild && !(fname[len-1] in ['/', '\'])) {
  60. ;        type = chmod(0, fname);
  61. ;        if (type & directory) {
  62. ;            strappend(fname, "\");
  63. ;        }
  64. ;
  65. ;    if (fname[len-1] in ['/', '\'])
  66. ;        strappend(fname, "*.*");
  67. ;
  68. ;    depth = 0;
  69. ;    eval(checkspec);
  70. ;    }
  71. ;
  72.  
  73.     extrn    _args:near,_shift:near,argc:word,argv:word
  74.     extrn    new:near,sprintf:near
  75.     extrn    rindex:near, strcmp:near
  76.  
  77. stdout    equ    1
  78. stderr    equ    2
  79. fnameo    equ    158        ; offset of filename from CS.
  80. fattrib    equ    149        ; offset of file attribute byte from CS.
  81.  
  82. dos    macro    fn
  83.     mov    ah, fn
  84.     int    21h
  85.     endm
  86.  
  87. move    macro    w2, w1
  88.     mov    ax, w1
  89.     mov    w2, ax
  90.     endm
  91.  
  92. movb    macro    b2, b1
  93.     mov    al, b1
  94.     mov    b2, al
  95.     endm
  96.  
  97. code    segment    public 'CODE'
  98. assume cs:code,ds:code
  99.  
  100.     org    100h
  101.  
  102. ls    proc    near
  103.     jmp    main
  104.  
  105.     db    27
  106.     db    '[2J'
  107.     db    'ls; 1985 Dan Kegel & Chris Worell, Pasadena, CA', 13, 10
  108.     db    'Take this, brother, may it serve you well.', 13, 10
  109. umsg:    db    'Usage: ls {-alrstR1} name', 13, 10
  110. umsgl    equ    $-umsg
  111.     db    26        ; eof for random prints
  112.  
  113. dotdot    db    "..",0        ; | for .. kludge
  114.  
  115. opt_a    db    ?
  116. opt_l    db    ?
  117. opt_r    db    ?
  118. opt_s    db    ?
  119. opt_t    db    ?
  120. opt_RR    db    ?
  121. opt_1    db    ?
  122. nopts    equ    7
  123.  
  124. sea_atr    dw    ?        ; attributes to use when searching.
  125. colcount    db    ?
  126.  
  127. depth    dw    ?
  128. fname    dw    ?
  129. wild    db    ?
  130.  
  131. number:    db    10 dup (?)        ; where we put string of dirsize
  132.  
  133. ; Directory attribute field bits
  134. A_BACKNEEDED    equ    20h        ; set if written since last backup
  135. A_DIRECTORY    equ    10h
  136. A_VOLUME    equ    8h
  137. A_HIDDEN    equ    4h
  138. A_SYSTEM    equ    2h
  139. A_READONLY    equ    1h
  140.  
  141. sattribs: db    'dhsrwx',0
  142. nattribs equ    6
  143.  
  144. scontrol: db    ' %8ld ',0
  145. fcontrol: db    '%-14s',0
  146. lcontrol: db    '%s %8ld  %s %2d',0
  147. ycontrol: db    '  %4d  ',0
  148. tcontrol: db    ' %2d:%02d  ',0
  149.  
  150. pbuffer: db    90 dup (?)
  151.  
  152. months:    db    'Jan',0,'Feb',0,'Mar',0,'Apr',0,'May',0,'Jun',0
  153.     db    'Jul',0,'Aug',0,'Sep',0,'Oct',0,'Nov',0,'Dec',0
  154.     db    'Time To Get A New Calendar', 0
  155.  
  156. ; Hee,hee,heeeeheee!  Are we Unix yet?
  157. EXT_BAT:    db    'bat',0
  158. EXT_COM:    db    'com',0
  159. EXT_EXE:    db    'exe',0
  160.  
  161. pe_dp    db    ?        ; last level- if it changes, do a CRLF
  162.  
  163. main:
  164.     call    _args                ; Get arguments.
  165.     cld
  166.  
  167.     mov    al, 0                ; reset all switches
  168.     mov    di, offset opt_a
  169.     mov    cx, nopts
  170.     rep    stosb
  171.  
  172. bigalp:    cmp    argc, 1
  173.     jb    no_opts
  174.         mov    si, argv[2]
  175.         lodsb
  176.         cmp    al, '-'
  177.         jnz    no_opts
  178.  
  179.         ; He gave some options; set the needed flags.
  180.         ; There are so many options for ls that I'll just ignore
  181.         ; unimplemented options.
  182.  
  183. aloop:        lodsb
  184.         or    al, al
  185.         jz    adone
  186.         cmp    al, 'a'
  187.         jnz    AL1
  188.             mov    opt_a, al
  189.             jmp    short aloop
  190. AL1:        cmp    al, 'l'
  191.         jnz    AL2
  192.             mov    opt_l, al    ; some options force -1
  193.             mov    opt_1, al
  194.             jmp    short aloop
  195. AL2:        cmp    al, 's'
  196.         jnz    AL3
  197.             mov    opt_s, al
  198.             jmp    short aloop
  199. AL3:        cmp    al, 'R'
  200.         jnz    AL4
  201.             mov    opt_RR, al
  202.             jmp    short aloop
  203. AL4:        cmp    al, '1'
  204.         jnz    AL5
  205.             mov    opt_1, al
  206.             jmp    short aloop
  207. AL5:        cmp    al, 'r'
  208.         jnz    AL6
  209.             mov    opt_r, al
  210.             jmp    short aloop
  211. AL6:        cmp    al, 't'
  212.         jnz    AL7
  213.             mov    opt_t, al
  214.             jmp    short aloop
  215.  
  216. AL7:        jmp    prt_usage
  217.  
  218. adone:
  219.         call    _shift
  220.         dec    argc
  221.         jmp    bigalp    ; maybe he said -R -t or something like that
  222.  
  223. no_opts:
  224. ;    sea_atr = directory;        /* includes normal files */
  225. ;    if (opt_a)
  226. ;        sea_atr = hidden + directory;
  227.     mov    sea_atr, 10h
  228.     test    opt_a, -1
  229.     jz    no_opta
  230.         mov    sea_atr, 12h
  231. no_opta:
  232.  
  233.     ;    char    fname[128];
  234.  
  235.     mov    cx, 128
  236.     call    new
  237.     mov    fname, bx
  238.  
  239.     ;    if (argv > 1) error;
  240.     cmp    argc, 1
  241.     jbe    K1
  242. prt_usage:    mov    cx, umsgl    ; give syntax error
  243.         mov    dx, offset umsg
  244.         mov    bx, stderr    ; write to error device...
  245.         dos    40h
  246.         mov    al, 1        ; status = error
  247.         dos    4ch        ; terminate process.
  248. K1:
  249.     ;    fname[0] = '/0';
  250.     mov    di, fname
  251.     mov    byte ptr [di], 0
  252.  
  253.     ;    if (argc = 1) strcpy(fname, argv[2]);
  254.     cmp    argc, 1
  255.     jnz    K2
  256.         mov    si, argv[2];
  257. arcloop:    lodsb
  258.         cmp    al, 0
  259.         stosb
  260.         jnz    arcloop
  261.  
  262. K2:
  263.     ;-------------------------------
  264.     ;    /* No argument, or default directory? */
  265.     ;    if (fname[0] == '\0' || (fname[0] == '.' && fname[1] == '\0'))
  266.     mov    si, fname
  267.     lodsb
  268.     cmp    al, 0
  269.     jz    B3
  270.     cmp    al, '.'
  271.     jnz    K3
  272.     lodsb
  273.     cmp    al, 0
  274.     jnz    K3
  275. B3:        
  276.     ;        /* leave a drive specifier for next if statement */
  277.     ;        fname[0] = 'A' + current_drive;
  278.     ;        fname[1] = ':';
  279.     ;        fname[2] = '\0';
  280.     ;        }
  281.         dos    19h            ; AL = disk (0=A, 1=B...)
  282.         mov    di, fname
  283.         add    al, 'A'
  284.         stosb
  285.         mov    al, ':'
  286.         stosb
  287.         mov    al, 0
  288.         stosb
  289. K3:
  290.  
  291.     ;---------------------------
  292.     ;    /* Drive only?  If so, get default directory for that drive */
  293.     ;    if (fname[1] == ':' && fname[2] == '\0') {
  294.     mov    si, fname
  295.     inc    si
  296.     lodsb
  297.     cmp    al, ':'
  298.     jnz    K4
  299.     lodsb
  300.     cmp    al, 0
  301.     jnz    K4
  302.     ;        fname[2] = '\';
  303.     ;        getpath(fname+3, toupper(fname[0])-'A'+1 );
  304.     ;        if (fname[3] != 0)        /* root directory */
  305.     ;            strappend(fname, "\");
  306.     ;        }
  307.     ;
  308.     mov    byte ptr [si-1], '\'
  309.     mov    dl, byte ptr [si-3]
  310.     sub    dl, 'a'-1
  311.     ja    islower
  312.         add    dl, 32
  313. islower:
  314.     ; Note that SI is pointing to the char just after the slash.
  315.     dos    47h        ; get cur dir of drive DL
  316.     mov    si, fname
  317.     cmp    byte ptr [si+3], 0
  318.     jz    K4        ; if root, don't add slash.
  319. L4:    lodsb
  320.     cmp    al, 0
  321.     jnz    L4
  322.     mov    byte ptr [si-1], '\'
  323.     mov    byte ptr [si], 0
  324.  
  325. K4:
  326.     
  327. ;    /* Is it wildcarded?  If so, it cannot be a directory. */
  328. ;    for (i=0; i<strlen(fname); i++)
  329. ;        wild = (fname[i] in ['?', '*']);
  330. ;
  331.     mov    wild, -1
  332.     mov    si, fname
  333. L4A:    lodsb
  334.     cmp    al, '?'
  335.     jz    K4A
  336.     cmp    al, '*'
  337.     jz    K4A
  338.     cmp    al, 0
  339.     jnz    L4A
  340.  
  341.     mov    wild, 0
  342. K4A:
  343.  
  344.  
  345.     ;--------------------------
  346.     ;    /* Is it a directory (does it end with a slash) ? */
  347.     ;    if (!wild && !(fname[len-1] in ['/', '\'])) {
  348.     
  349.     test    wild, -1
  350.     jnz    K5
  351.  
  352.     mov    si, fname
  353. L5:    lodsb
  354.         cmp    al, 0
  355.         jnz    L5
  356.  
  357.     sub    si, 2        ; point to last nonnull
  358.     lodsb            ; get it
  359.     cmp    al, '\'
  360.     jz    K5
  361.     cmp    al, '/'
  362.     jz    K5        ; if AL in ['/', '\'], skip IF clause.
  363.  
  364.     ;        type = chmod(0, fname);
  365.     ;        if (type & directory) {
  366.     ;            strappend(fname, "\");
  367.     ;        }
  368.         mov    dx, fname
  369.         ; | kludge: if [dx] = "..", file is a directory...
  370.         push    si
  371.         mov    si, dx
  372.         mov    di, offset dotdot
  373.         call    strcmp
  374.         pop    si
  375.         jz    isdotdot
  376.  
  377.         mov    al, 0
  378.         DOS    43h
  379.         jc    K5            ; not found- ergo not directory
  380.         and    cl, 10h            ; directory?
  381.         jz    K5            ; nope; skip.
  382.  
  383. isdotdot:        ; Note that SI still points to null @ end of string.
  384.             mov    di, si
  385.             mov    al, '\'
  386.             stosb
  387.             mov    al, 0
  388.             stosb
  389.  
  390. K5:
  391.  
  392. ;    if (fname[len-1] in ['/', '\'])
  393.  
  394.     mov    si, fname
  395. L6:    lodsb
  396.     cmp    al, 0
  397.     jnz    L6
  398.  
  399.     sub    si, 2        ; point to last nonnull
  400.     lodsb            ; get it
  401.     cmp    al, '\'
  402.     jz    B6
  403.     cmp    al, '/'
  404.     jnz    K6        ; if AL not in ['/', '\'], skip IF clause.
  405.  
  406. B6:
  407. ;        strappend(fname, "*.*");
  408.         mov    di, si
  409.         mov    al, '*'
  410.         stosb
  411.         mov    al, '.'
  412.         stosb
  413.         mov    al, '*'
  414.         stosb
  415.         mov    al, 0
  416.         stosb
  417.  
  418.         mov    si, di
  419. K6:
  420.     call    checkspec    ; returns pointer to list in BX
  421.     call    sort_struct    ; sorts list, returning new BX
  422.  
  423.     mov    word ptr depth, 0
  424.     mov    byte ptr pe_dp, 1
  425.     mov    colcount, 0
  426.  
  427.     call    print_struct    ; prints list
  428.  
  429.     ; If we haven't yet, finish off with a cr/lf.
  430.     cmp    colcount, 0
  431.     jz    all_done
  432.         mov    dl, 13
  433.             DOS    2
  434.             mov    dl, 10
  435.             DOS    2
  436. all_done:
  437.     mov    al, 0
  438.     DOS    4CH        ; terminate
  439. ls    endp
  440.  
  441.  
  442. ;------
  443. indent    proc    near
  444.     push    cx
  445.     push    dx
  446.     cmp    colcount, 0
  447.     jnz    noind
  448.         mov    cx, depth
  449.         add    cx, cx
  450.         add    cx, depth
  451.         sub    cx, 3
  452.         jbe    noind
  453.         mov    dl, ' '
  454. LI1:        DOS    2
  455.         loop    LI1
  456. noind:    pop    dx
  457.     pop    cx
  458.     ret
  459. indent    endp
  460.  
  461.  
  462. ;----- Main Program Stuff --------------------------------------------
  463.  
  464.  
  465. ;----- Definition of local variables for checkspec -------------------
  466. oldlen    equ    0
  467. dirsize    equ    2
  468. sibling    equ    6        ; points to things at same level
  469. kids    equ    8        ; points to children
  470. finder    equ    10
  471. f_name    equ    finder+30
  472. f_attr    equ    finder+21
  473. f_time    equ    finder+22
  474. f_date    equ    finder+24
  475. f_size    equ    finder+26
  476. findlen    equ    43        ; finder is 43 bytes long
  477.  
  478. ;----- Definition of entries in the data structure -------------------------
  479. e_size equ 0        ; longint;    { totalled }
  480. e_prev equ 4        ; entryptr;    { entry found a moment ago }
  481. e_kids equ 6        ; entryptr;    { only nonzero for directories }
  482. e_date equ 8        ; word;
  483. e_time equ 10        ; word;
  484. e_attr equ 12        ; byte;        { only bit 3 counts during sort }
  485. e_name equ 13        ; string[15];    { in lowercase, padded with nulls }
  486. entrylen equ    28
  487.  
  488. ;---------------------------------------------------------------------------
  489.  
  490.  
  491. ;---- Compare_Entries ---------------------------------------------------
  492. ; Called with one entryptr in SI, one in DI.
  493. ; Return with Carry set if di > si.
  494. ; Compare names unless -t, in which case compare dates×.
  495. ; Sort order is reversed if -r, except that results are always sorted
  496. ; to yield directories at the deepest part of the list.
  497.  
  498. compare_entries    proc    near
  499.  
  500.     push    si
  501.     push    di
  502.  
  503.     ; compare attributes, to force pretty output.
  504.     ; (That is, if DI is a directory and SI isn't, set carry.)
  505.     mov    al,[si][e_attr]
  506.     mov    ah,[di][e_attr]
  507.     and    ax, 1010h        ; mask out all but dir status
  508.     cmp    al,ah
  509.     jnz    comp_done        ; we're done if not equal.
  510.  
  511.     test    opt_r, -1    ; reverse sort?
  512.     jz    comp_norev    ; nope.
  513.         xchg    si, di    ; yep.
  514. comp_norev:
  515.  
  516.     test    opt_t, -1    ; sort by time?
  517.     jnz    comp_times    ; yes...
  518.  
  519.         ; Compare names.
  520.         mov    cx, 15        ; length of name field in bytes
  521.         add    si, e_name
  522.         add    di, e_name    ; point them to start of name field
  523.         rep    cmpsb
  524.         jmp    short comp_done
  525. comp_times:
  526.         ; Compare dates, then times.
  527.         xchg    si, di
  528.         mov    cx, 2
  529.         add    si, e_date
  530.         add    di, e_date
  531.         rep    cmpsw
  532. comp_done:
  533.     pop    di
  534.     pop    si
  535.  
  536.     ret
  537.  
  538. compare_entries    endp
  539.  
  540. ;---- sort_list ----------------------------------------------------------
  541. ; procedure sort_list(var bx: entryptr);
  542. ;
  543. ; Sorts one list of the data structure.  Caller must use the returned BX
  544. ; as his new pointer to the start of the list.
  545. ; Uses simple bubble sort.
  546. ;
  547. ; var
  548. ;    fore, back, fartherback: entryptr;
  549. ;    flip      : boolean;
  550. ; begin
  551. ;    if (bx != nil) then repeat
  552. ;        flip := false;
  553. ;        fartherback := &bx;    { more or less }
  554. ;        back := bx;
  555. ;        fore := bx^.prev;
  556. ;        while (fore != nil) do begin
  557. ;            compare(si=fore, di=back);
  558. ;            if carry then begin
  559. ;                back^.prev := fore^.prev;
  560. ;                fore^.prev := back;
  561. ;                fartherback^.prev := fore;
  562. ;                swap (fore, back);
  563. ;                flip := true;
  564. ;                end;
  565. ;            fartherback := back;
  566. ;            back := fore;
  567. ;            fore := fore^.prev;
  568. ;            end;
  569. ;        until not flip;
  570. ;    end;
  571. ;
  572. ; si = fore, di = back, bx = fartherback
  573.  
  574. root    equ    0
  575. flip    equ    2
  576.  
  577. sort_list    proc    near
  578.     push    bp
  579.     sub    sp, 4        ; allocate locals (We don't need to be
  580.     mov    bp, sp        ;   re-entrant, but what the heck)
  581.  
  582.     mov    [bp][root], bx
  583.     or    bx, bx
  584.     jz    sort_done;
  585.  
  586. sort_r:        mov    byte ptr [bp][flip], 0
  587.         lea    bx, [bp][root]        ; bx always points to a .prev
  588.         mov    di, [bx]        ; whereas *di is a whole record
  589.         mov    si, [di][e_prev]
  590.  
  591. sort_w:            or    si, si
  592.             jz    sort_wx        ; while's exit
  593.  
  594.             call    compare_entries
  595.  
  596. ;            if carry then begin
  597. ;                back^.prev := fore^.prev;
  598. ;                fore^.prev := back;
  599. ;                fartherback^.prev := fore;
  600. ;                swap (fore, back);
  601. ;                flip := true;
  602. ;                end;
  603.             jae    no_flippo
  604.                 move    [di][e_prev], [si][e_prev]
  605.                 mov    [si][e_prev], di
  606.                 mov    [bx], si
  607.                 xchg    si, di
  608.                 mov    byte ptr [bp][flip], -1
  609. no_flippo:
  610. ;            fartherback := back;
  611. ;            back := fore;
  612. ;            fore := fore^.prev;
  613.             lea    bx, [di][e_prev]
  614.             mov    di, si
  615.             mov    si, [si][e_prev]
  616.  
  617. ;            end;
  618.             jmp    sort_w
  619. sort_wx:
  620.  
  621. ;        until not flip;
  622.         test    byte ptr [bp][flip], -1
  623.         jnz    sort_r
  624.  
  625. ;    end;
  626. sort_done:
  627.     mov    bx, [bp][root]
  628.  
  629.     add    sp, 4
  630.     pop    bp
  631.     ret
  632.  
  633. sort_list    endp
  634.  
  635.  
  636. ;---- sort_struct ---------------------------------------------------------
  637. ; procedure sort_struct(var bx: entryptr);
  638. ; { Sorts entire data structure.  Caller must use returned BX. }
  639. ; begin
  640. ;    sort_list(bx);
  641. ;    while (bx != nil) do begin
  642. ;        sort_list(bx^.kids);
  643. ;        bx := bx^.prev;
  644. ;        end;
  645. ;    end;
  646.  
  647. sort_struct    proc    near
  648.     call    sort_list
  649.     push    bx
  650. ss_w:
  651.     or    bx, bx
  652.     jz    ss_done
  653.         push    bx
  654.         mov    bx, [bx][e_kids]
  655.         call    sort_struct
  656.         pop    si
  657.         mov    [si][e_kids], bx    ; use new BX returned by Sort
  658.         mov    bx, [si][e_prev]
  659.         jmp    ss_w
  660. ss_done:
  661.     pop    bx
  662.     ret
  663. sort_struct    endp
  664.  
  665.  
  666.     page
  667.  
  668. ;---- print_struct ---------------------------------------------------------
  669. ; procedure print_struct(bx: entryptr);
  670. ;
  671. ; Prints out the tree.
  672. ;
  673. print_struct    proc    near
  674.     inc    depth
  675.  
  676. ps_loop:
  677.     cmp    bx, 0
  678.     jz    ps_done
  679.         call    printentry
  680.  
  681.         push    [bx][e_prev]
  682.         mov    bx, [bx][e_kids]
  683.         cmp    bx, 0
  684.         jz    ps_nokids
  685.             call    print_struct
  686. ps_nokids:    pop    bx
  687.         jmp    ps_loop
  688. ps_done:
  689.  
  690.     dec    depth
  691.     ret
  692.  
  693. print_struct    endp
  694.  
  695. ;---- printentry -----------------------------------------------------------
  696. ;
  697. ; printentry(bx: entryptr);
  698. ; {
  699. ;    /* Print the entry according to the options given */
  700. ;    if (opt_a || !([bx][e_attr] && hidden)) {
  701. ;
  702. ;    }
  703.  
  704. printentry    proc    near
  705.  
  706.     test    opt_a, -1
  707.     jnz    doentry            ; Unless -a option,
  708.     lea    si, [bx][e_name]
  709.     lodsb
  710.     cmp    al, '.'
  711.     jne    doentry            ; if starts with dot, don't print.
  712.         jmp    peend
  713. doentry:
  714.     test    opt_1, -1
  715.     jnz    doreturn
  716.     mov    ax, depth
  717.     cmp    al, pe_dp
  718.     jnz    doreturn
  719.     mov    cx, 15
  720.     test    opt_s, -1
  721.     jz    nosopt
  722.     mov    cx, 25
  723. nosopt:    mov    al, colcount
  724.     xor    ah,ah
  725.     inc    ax
  726.     mul    cx
  727.     mov    cx, depth
  728.     dec    cx        ;  depends what start value is
  729.     add    ax, cx
  730.     add    ax, cx
  731.     add    ax, cx
  732.     cmp    ax, 80    ;?79
  733.     jnge    noreturn
  734. doreturn:
  735.     mov    dl, 13
  736.     DOS    2
  737.     mov    dl, 10
  738.     DOS    2
  739.     mov    colcount, 0
  740. noreturn:
  741.     test    opt_l, -1
  742.     jnz    nr1
  743.     jmp    notpl
  744. nr1:
  745.     push    di
  746.     mov    di, offset sattribs    ;? is di available
  747.     ; stuff for directory, temporary, or volumename (t/d/v)
  748.     test    byte ptr [bx][e_attr], A_DIRECTORY
  749.     jz    pe_nd
  750.         mov    al, 'd'
  751.         jmp    short pe_gotspecial
  752. pe_nd:    ; See if file created at 25 O'Clock (see BLAM.COM and SUICIDE.COM)
  753.     cmp    word ptr [bx][e_time], (25 * 2048)
  754.     jnz    pe_ntemp
  755.         mov    al, 't'
  756.         jmp    short pe_gotspecial    
  757. pe_ntemp:
  758.     mov    al, '-'
  759. pe_gotspecial:
  760.     stosb
  761.     mov    al, '-'
  762.     ; stuff for hidden -h
  763.     test    byte ptr [bx][e_attr], A_HIDDEN
  764.     jz    pe_nh
  765.         mov    al, 'h'
  766. pe_nh:    stosb
  767.     mov    al, '-'
  768.     ; stuff for system -s
  769.     test    byte ptr [bx][e_attr], A_SYSTEM    ; (sic)
  770.     jz    pe_ns
  771.         mov    al, 's'
  772. pe_ns:
  773.     stosb
  774.     mov    al, '-'
  775.  
  776.     ; stuff for read -r
  777.     mov    al, 'r'
  778.     stosb
  779.     mov    al, '-'
  780.     ; stuff for write -w
  781.     test    byte ptr [bx][e_attr], A_READONLY
  782.     jnz    pe_nr
  783.         mov    al, 'w'
  784.         jmp    short pe_gotr
  785. pe_nr:
  786.     test    byte ptr [bx][e_attr], A_DIRECTORY
  787.     jz    pe_gotr
  788.         mov    al, 'w'
  789. pe_gotr:
  790.     stosb
  791.     push    di
  792.  
  793.     ; stuff for executable -x
  794.     ; executable = (directory || terminator in {.bat, .com, .exe}) 
  795.     test    byte ptr [bx][e_attr], A_DIRECTORY
  796.     jnz    pe_isx
  797.     lea    si, [bx][e_name]    ; get pointer to null-term name
  798.     mov    al, '.'
  799.     call    rindex            ; get pointer to extension
  800.     or    si, si
  801.     mov    al, '-'
  802.     jz    pe_gotx
  803.     inc    si
  804.     mov    ax, si            ; save extension
  805.     mov    di, offset EXT_COM
  806.     call    strcmp
  807.     jz    pe_isx
  808.  
  809.     mov    si, ax
  810.     mov    di, offset EXT_EXE
  811.     call    strcmp
  812.     jz    pe_isx
  813.  
  814.     mov    si, ax
  815.     mov    di, offset EXT_BAT
  816.     call    strcmp
  817.     jz    pe_isx
  818.     mov    al, '-'
  819.     jmp    short pe_gotx
  820. pe_isx:    mov    al, 'x'
  821. pe_gotx:
  822.     pop    di
  823.     stosb
  824.     pop    di
  825.  
  826.     push    bx
  827.     mov    bp,sp
  828.     mov    ax, [bx][e_date]
  829.     and    ax, 31
  830.     push    ax
  831.     mov    ax, [bx][e_date]
  832.     mov    cl, 5
  833.     shr    ax, cl
  834.     and    ax, 15
  835.     dec    ax
  836.     add    ax, ax
  837.     add    ax, ax
  838.     add    ax, offset months
  839.     push    ax
  840.     mov    ax, [bx][e_size]
  841.     mov    dx, [bx][e_size+2]
  842.     push    dx
  843.     push    ax
  844.     mov    ax, offset sattribs
  845.     ;mov    ax, [bx][e_attr]    ; temporary until attributes printed
  846.     push    ax
  847.     mov    ax, offset lcontrol
  848.     push    ax
  849.     mov    ax, offset pbuffer
  850.     push    ax
  851.     call    sprintf
  852.     mov    sp, bp
  853.     pop    bx
  854.     call    printbuff
  855.     DOS    2AH    ;cx=year,dh=month,dl=day
  856.     mov    ax, cx
  857.     sub    ax, 1980
  858.     mov    cl, 9
  859.     shl    ax, cl
  860.     add    al, dl
  861.     mov    dx, ax        ; this year's packed year
  862.     push    bx
  863.     mov    bp, sp
  864.     mov    ax, [bx][e_date]
  865.     cmp    ax, dx
  866.     jl    doyear
  867.     add    dx, 200H    ; beginning of next year
  868.     cmp    ax, dx
  869.     jl    dotime
  870. doyear:    mov    cl, 9
  871.     shr    ax, cl
  872.     and    ax, 127
  873.     add    ax, 1980    ;1980 is base year for years
  874.     push    ax
  875.     mov    ax, offset ycontrol
  876.     jmp    dofield
  877. dotime:    mov    ax, [bx][e_time]
  878.     mov    cl, 5
  879.     shr    ax, cl
  880.     and    ax, 63
  881.     push    ax
  882.     mov    ax, [bx][e_time]
  883.     mov    cl, 11
  884.     shr    ax, cl
  885.     and    ax, 31
  886.     push    ax
  887.     mov    ax, offset tcontrol
  888. dofield:
  889.     push    ax
  890.     mov    ax, offset pbuffer
  891.     push    ax
  892.     call    sprintf
  893.     mov    sp, bp
  894.     pop    bx
  895.     call    printbuff
  896.     jmp    dofile
  897.  
  898. notpl:    test    opt_s, -1
  899.     jz    dofile
  900.     push    bx
  901.     mov    bp, sp
  902.     mov    ax, [bx][e_size]
  903.     mov    dx, [bx][e_size+2]
  904.     push    dx
  905.     push    ax
  906.     mov    ax, offset scontrol
  907.     push    ax
  908.     mov    ax, offset pbuffer
  909.     push    ax
  910.     call    sprintf
  911.     mov    sp, bp
  912.     pop    bx
  913.     call    printbuff
  914. dofile:    call    indent
  915.     mov    ax, depth
  916.     mov    pe_dp, al
  917.     push    bx
  918.     mov    bp, sp
  919.     lea    dx, [bx][e_name]
  920.     mov    cx, 15
  921.     test    byte ptr [bx][e_attr], 10H
  922.     jz    notdir
  923.     cld
  924.     mov    di, dx
  925.     mov    al, 0
  926.     repnz    scasb
  927.     mov    byte ptr [di-1],'\'
  928. notdir:    lea    ax, [bx][e_name]
  929.     push    ax
  930.     mov    ax, offset fcontrol
  931.     push    ax
  932.     mov    ax, offset pbuffer
  933.     push    ax
  934.     call    sprintf
  935.     mov    sp, bp
  936.     pop    bx
  937.     call    printbuff
  938.     inc    colcount
  939. peend:    ret
  940.  
  941. printentry    endp
  942.  
  943.  
  944. printbuff proc    near
  945.  
  946.     push    bx
  947.     mov    dx, offset pbuffer
  948.     mov    cx, 90
  949.     cld
  950.     mov    di, dx
  951.     mov    al, 0
  952.     repnz    scasb
  953.     mov    cx, di
  954.     dec    cx
  955.     mov    dx, offset pbuffer
  956.     sub    cx, dx
  957.     mov    bx, stdout
  958.     DOS    40H
  959.     pop    bx
  960.     ret
  961. printbuff    endp
  962.  
  963.  
  964.  
  965.  
  966. ;----- strlen -------
  967. ; Call it with string @ SI:DS.
  968. ; Returns with length in CX, and SI pointing to the null at end of string.
  969.  
  970. strlen    proc    near
  971.  
  972.     mov    cx, 0
  973. SL1:    lodsb
  974.     inc    cx
  975.     cmp    al, 0
  976.     jnz    SL1
  977.     dec    si
  978.     ret
  979.  
  980. strlen    endp
  981.  
  982. ;---- stripwild ---------
  983. ; Call with SI=start of string to strip.
  984.  
  985. stripwild    proc    near
  986.  
  987.     push    si
  988.     call    strlen
  989.     pop    di
  990.     dec    di
  991.  
  992.     std                ; search from string end back
  993.     mov    wild, 0            ; no wildcards found yet
  994. SW_loop:    lodsb
  995.         cmp    al, '*'
  996.         jz    sw_wild
  997.         cmp    al, '?'
  998.         jnz    sw_nw
  999. sw_wild:        mov    wild, 1
  1000. sw_nw:        cmp    al, '\'
  1001.         jz    SW_gotit
  1002.         cmp    al, '/'
  1003.         jz    SW_gotit
  1004.         cmp    al, ':'
  1005.         jz    SW_gotit
  1006.         cmp    si, di
  1007.         jnz    SW_loop
  1008. SW_gotit:
  1009.     cld
  1010.     test    wild, 1
  1011.     jz    SW_forgetit            ; jump if no wilds found
  1012.         add    si, 2
  1013.         mov    byte ptr [si], 0
  1014. SW_forgetit:
  1015.     ret
  1016. stripwild    endp
  1017.  
  1018.  
  1019. ;---- save_entry -------------------------------------------------------------
  1020. ; To be called from within checkspec.  Accesses local variables thereof.
  1021. ;
  1022. ; Places a record of the current entry into the data structure.
  1023. ; Converts name to lowercase, pads to 15 nulls.
  1024. ; procedure save_entry(bp: finderptr);
  1025. ; var
  1026. ;       newentry: entryptr;
  1027. ; begin
  1028. ;    new(newentry);
  1029. ;    with newentry^ do begin
  1030. ;        prev := [bp][sibling];
  1031. ;        [bp][sibling] := newentry;
  1032. ;        kids := [bp][kids];
  1033. ;        size := [bp][f_size];
  1034. ;        attr := [bp][f_attr];
  1035. ;        name := upperstring([bp][f_name]);
  1036. ;        pad(name, 15,0);
  1037. ;        end;
  1038. ;    end;
  1039.  
  1040. save_entry    proc    near
  1041.  
  1042.     mov    cx, entrylen
  1043.     call    new        ; bx = newentry;
  1044.  
  1045.     move    [bx][e_prev], [bp][sibling]
  1046.     mov    [bp][sibling], bx
  1047.     move    [bx][e_kids], [bp][kids]
  1048.     move    [bx][e_size], [bp][f_size]
  1049.     move    [bx][e_size+2], [bp][f_size+2]
  1050.     movb    [bx][e_attr], [bp][f_attr]
  1051.     move    [bx][e_date], [bp][f_date]
  1052.     move    [bx][e_time], [bp][f_time]
  1053.  
  1054.     lea    si, [bp][f_name]
  1055.     lea    di, [bx][e_name]
  1056.     mov    cx, 15        ; Field is 15 bytes.
  1057.  
  1058. se_1:        lodsb
  1059.         cmp    al, 'A'
  1060.         jb    se_2
  1061.         cmp    al, 'Z'
  1062.         ja    se_2
  1063.             add    al, 32
  1064. se_2:        stosb
  1065.         cmp    al, 0
  1066.         loopnz    se_1
  1067.  
  1068.     dec    di
  1069.     inc    cx
  1070.  
  1071.     mov    al,0
  1072.     rep    stosb        ; pad with nulls.
  1073.                 ; only needs 1 (2 if a directory)
  1074.     ret
  1075.  
  1076. save_entry    endp
  1077.     
  1078.  
  1079.  
  1080.     page
  1081. ;------------------------------------------------------------------------
  1082. ; /* checkspec finds and prints the name of each file */
  1083. ; /* which matches the given filespec. */
  1084. ; /* Also returns total size of all files in DX:AX. */
  1085. ; /* Returns sibling list pointer in BX. */
  1086. ; long checkspec;
  1087. ; {
  1088. ;    int    oldlen;
  1089. ;    int    dirsize = 0;
  1090. ;    char    finder[32];
  1091. ;
  1092. ;    oldlen = strlen(fname);
  1093. ;    depth++;
  1094. ;    set_DTA(finder);
  1095. ;    findfirst(fname, finder, sea_atr);
  1096. ;    strip_wildcards(fname);
  1097. ;
  1098. ;    do {
  1099. ;        dirsize += finder.size;
  1100. ;        printentry(finder.name);
  1101. ;        if (opt_RR && finder.type==directory && finder.name[0]!='.') {
  1102. ;            strcpy(fname+oldlen, finder.name, "\*.*");
  1103. ;            dirsize += checkdir;
  1104. ;            set_DTA(finder);
  1105. ;            }
  1106. ;        } while findnext;
  1107. ;
  1108. ;    fname[oldlen]='\0';
  1109. ;    if (opt_s)
  1110. ;        printentry(fname);
  1111. ;    depth--;
  1112. ;    return(dirsize);
  1113. ;    }
  1114.  
  1115.     page
  1116.  
  1117. ; long checkspec() {
  1118. checkspec    proc    near
  1119.  
  1120. ; 0    int    oldlen;
  1121. ; 4    long    dirsize = 0;
  1122. ; 6     word    sibling = nil;
  1123. ; 8    word    kids    = nil;
  1124. ; 10    char    finder[43];
  1125. locals    equ    finder+findlen
  1126.     push    bp
  1127.     sub    sp, locals    ; allocate room for locals
  1128.     mov    bp, sp
  1129.  
  1130. ;    dirsize = 0; sibling = nil; kids = nil;
  1131.     mov    word ptr [bp][dirsize], 0
  1132.     mov    word ptr [bp][dirsize+2], 0
  1133.     mov    word ptr [bp][sibling], 0
  1134. ;    mov    word ptr [bp][kids], 0
  1135.  
  1136. ;    set_DTA(finder);
  1137.     lea    dx, [bp][finder]
  1138.     DOS    1AH
  1139.  
  1140. ;    findfirst(fname, finder, attribs(opt_a));
  1141.     mov    dx, fname
  1142.     mov    cx, 10H
  1143.     test    opt_a, -1
  1144.     jz    findem
  1145.         mov    cx, 17H
  1146. findem:    DOS    4EH
  1147.     jc    while            ; if none found, skip whole business.
  1148.  
  1149. ;    strip_wildcards(fname);        /* kill everything back to slash */
  1150.     mov    si, fname
  1151.     call    stripwild
  1152.     mov    si, fname
  1153.     call    strlen
  1154.     mov    [bp][oldlen], si
  1155.  
  1156. ;    while (found) do {
  1157.     clc
  1158. while:    jc    endwhile
  1159.  
  1160. ;        dirsize += finder.size;
  1161.         mov    ax, [bp][f_size]
  1162.         add    [bp][dirsize], ax
  1163.         mov    ax, [bp][f_size+2]
  1164.         adc    [bp][dirsize+2], ax
  1165.  
  1166. ;        finder.kids := nil;
  1167. ;        ( In case last time thru was a directory. }
  1168.         mov    word ptr [bp][kids], 0
  1169.  
  1170. ;        if (opt_RR && finder.type == directory) {
  1171.         test    opt_RR, -1
  1172.         jz    KC2
  1173.         test    byte ptr [bp][f_attr], 10h
  1174.         jz    KC2
  1175.  
  1176. ;            strcpy(fname+oldlen, finder.name, "\*.*");
  1177.             mov    di, [bp][oldlen]
  1178.             lea    si, [bp][f_name]
  1179.             cmp    byte ptr [si], '.' ; is it "." or ".." ?
  1180.             jz    KC2           ; if so, don't recurse!!!!
  1181. LC2:                lodsb
  1182.                 cmp    al, 0
  1183.                 jz    BC2
  1184.                 stosb
  1185.                 jmp    LC2
  1186. BC2:            mov    al, '\'
  1187.             stosb
  1188.             mov    al, '*'
  1189.             stosb
  1190.             mov    al, '.'
  1191.             stosb
  1192.             mov    al, '*'
  1193.             stosb
  1194.             mov    al, 0
  1195.             stosb
  1196.  
  1197.             call    checkspec
  1198.  
  1199. ;            finder.kids := checkspec.sibling;
  1200. ;            ( This is only to pass to save_entry. }
  1201.             mov    [bp][kids], bx
  1202.  
  1203. ;            dirsize += checkspec.length;
  1204.             add    [bp][dirsize], ax
  1205.             adc    [bp][dirsize+2], dx
  1206.  
  1207. ;            finder.size += checkspec.length;
  1208.             add    [bp][f_size], ax
  1209.             adc    [bp][f_size+2], dx
  1210.  
  1211. ;            set_DTA(finder);
  1212.             lea    dx, [bp][finder]
  1213.             DOS    1AH
  1214. ;            }
  1215.  
  1216. KC2:            call    save_entry
  1217.  
  1218. ;        } while findnext;
  1219.         DOS    4FH
  1220.         JMP    WHILE
  1221. endwhile:
  1222.  
  1223. ;    fname[oldlen]='\0';
  1224.     mov    si, [bp][oldlen]
  1225.     mov    byte ptr [si], 0
  1226.  
  1227. ;    return(dirsize, sibling);
  1228. ;    }
  1229.     mov    ax, [bp][dirsize]
  1230.     mov    dx, [bp][dirsize+2]
  1231.     mov    bx, [bp][sibling]
  1232.  
  1233.     add    sp, locals
  1234.     pop    bp
  1235.     ret
  1236. checkspec    endp
  1237.  
  1238.  
  1239. code    ends
  1240.  
  1241.     end    ls
  1242.  
  1243.